home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / ada_pcdp / adas / state.pas < prev    next >
Pascal/Delphi Source File  |  1996-01-30  |  20KB  |  638 lines

  1. unit state;
  2.  
  3.   { Compile statements:
  4.       control structures and tasking statements }
  5.  
  6. interface
  7. uses global, util, expr;
  8. procedure statement(var dx: integer; level: integer);
  9.  
  10. implementation
  11.  
  12. procedure statement(var dx: integer; level: integer);
  13. var i: integer;
  14.     lcx: integer;  { dummy variable to receive var parameter }
  15.  
  16.   procedure compoundstatement;
  17.     { In Ada, there is no such thing as a compound statement.
  18.         This just compiles a sequence of statements }
  19.   begin
  20.     insymbol;
  21.     statement(dx, level);
  22.     while sy in statbegsys do
  23.       statement(dx, level);
  24.     if sy = endsy then insymbol else error(erkey)
  25.   end;
  26.  
  27.   procedure ifstatement;
  28.     {
  29.       if expression then statement 1; else statement 2;  compiles to:
  30.             lc0: expression
  31.             lc1: if false jump to lc2
  32.                  statement 1
  33.                  jump to lc3
  34.             lc2: statement 2
  35.             lc3:   (next statement)
  36.  
  37.       Since the jumps to lc2 and lc3 are emitted before the
  38.       values of the location counters are know, their addresses
  39.       must be remembered and fixed up afterwards. When an address
  40.       is fixed up the "assembly" listing is annotated (but the
  41.       listing itself is not fixed up).
  42.  
  43.       In Ada, the elsif construction causes a compilcation in
  44.       that an unknown number of jumps must be fixed up.
  45.       They are chained backwards and fixed up in a final loop.
  46.          The following shows an example with a single elsif
  47.          BEFORE the final jumps are fixed up:
  48.              10: expression 1
  49.              12: if false jump to 18
  50.              13: statement 1
  51.              17: jump to 0   -- end of chain
  52.              18: expression 2
  53.              23: if false jump to 27
  54.              24: statement 2
  55.              26: jump to 17  -- chain back to previous jump
  56.              27: statement 3
  57.              30:    (next statement)
  58.          Now lc2 will contain 26 which can be fixed to
  59.          jump to 30 and which contains the chain to 17 which
  60.          also needs to be fixed to jump to 30
  61.     }
  62.   var x: item;
  63.       lc1, lc2, lc3: integer;
  64.   begin
  65.     lc3 := 0;
  66.     repeat
  67.       insymbol;
  68.       expression(level, x);
  69.       if not (x.typ in [bools, notyp]) then error(ertyp);
  70.       lc1 := lc;
  71.       emit(11);
  72.       if sy = thensy then
  73.         begin
  74.         insymbol;
  75.         statement(dx, level);
  76.         while sy in statbegsys do
  77.           statement(dx, level);
  78.         if not (sy in [endsy, elsesy, elsif]) then error(erkey)
  79.         end
  80.       else error(erkey);
  81.       lc2 := lc;
  82.       emit1(10, lc3);
  83.       lc3 := lc2;
  84.       code[lc1].y := lc;
  85.       if listing then writeln(list, lc1:10, '   jump to here');
  86.     until sy <> elsif;
  87.     if sy = elsesy then
  88.       compoundstatement
  89.     else insymbol;
  90.     repeat
  91.       lc3 := code[lc2].y;
  92.       code[lc2].y := lc;
  93.       if listing then writeln(list, lc2:10, '   jump to here');
  94.       lc2 := lc3
  95.     until lc3 = 0;
  96.     if sy = ifsy then insymbol else error(erpun)
  97.   end;
  98.  
  99.   procedure loopstatement;
  100.     { Compiles infinite loops as well as loops with exit statements }
  101.   var x: item;
  102.       lc1, lc2: integer;
  103.   begin
  104.     lc2 := 0;
  105.     lc1 := lc;
  106.     insymbol;
  107.     while sy in statbegsys do
  108.       if sy = exitsy then
  109.         begin
  110.         insymbol;
  111.         if sy = when then insymbol else error(erkey);
  112.         expression(level, x);
  113.         if not (x.typ in [bools, notyp]) then error(ertyp);
  114.         emit(35);
  115.         lc2 := lc;
  116.         emit(11);
  117.         if sy = semicolon then insymbol else error(erpun)
  118.         end
  119.       else statement(dx, level);
  120.     if sy = endsy then
  121.       begin
  122.       insymbol;
  123.       if sy = loopsy then insymbol else error(erkey);
  124.       emit1(10, lc1);
  125.       if lc2 <> 0 then
  126.         begin
  127.         code[lc2].y := lc;
  128.         if listing then writeln(list, lc2:10, '   jump to here');
  129.         end
  130.       end
  131.   end;
  132.  
  133.   procedure whilestatement;
  134.     { Compiles while statements (exit is not allowed) }
  135.   var x: item;
  136.       lc1, lc2: integer;
  137.   begin
  138.     insymbol;
  139.     lc1 := lc;
  140.     expression(level, x);
  141.     if not (x.typ in [bools, notyp]) then error(ertyp);
  142.     lc2 := lc;
  143.     emit(11);
  144.     if sy <> loopsy then error(erkey);
  145.     compoundstatement;
  146.     emit1(10, lc1);
  147.     code[lc2].y := lc;
  148.     if listing then writeln(list, lc2:10, '   jump to here');
  149.     if sy = loopsy then insymbol else error(erpun)
  150.   end;
  151.  
  152.   procedure forstatement;
  153.     { Compiles for statements (exit is not allowed).
  154.         In Ada, the loop control variable is implicitly
  155.         declared in a new scope. Here the variable is entered in
  156.         the same scope which means that it if it has the same
  157.         name as a visible local variable, that variable will
  158.         be used contrary to Ada semantics.
  159.         If the variable name does not exist, it will be
  160.         declared as type integer. }
  161.   var cvt: types;
  162.       x: item;
  163.       i, lc1, lc2: integer;
  164.   begin
  165.     insymbol;
  166.     if sy = ident then
  167.       begin
  168.       i := loc(level, id);
  169.       if i <> 0 then insymbol
  170.         else begin
  171.         enter(id, variable, level);
  172.         insymbol;
  173.         i := t;
  174.         with tab[i] do
  175.           begin
  176.           typ := ints;
  177.           normal := true;
  178.           adr := dx;
  179.           dx := dx + 1
  180.           end
  181.         end;
  182.       if tab[i].obj = variable then
  183.         begin
  184.         cvt := tab[i].typ;
  185.         if not tab[i].normal then error(ertyp)
  186.         else emit2(0, tab[i].lev, tab[i].adr);
  187.         if not (cvt in [notyp, ints, bools, chars]) then error(ertyp)
  188.         end
  189.       else error(ertyp)
  190.       end
  191.     else error(erid);
  192.     if sy = insy then
  193.       begin
  194.       insymbol;
  195.       expression(level, x);
  196.       if x.typ <> cvt then error(ertyp)
  197.       end
  198.     else error(erpun);
  199.     if sy = colon then
  200.       begin
  201.       insymbol;
  202.       expression(level, x);
  203.       if x.typ <> cvt then error(ertyp)
  204.       end
  205.     else error(erkey);
  206.     lc1 := lc;
  207.     emit(14);
  208.     if sy <> loopsy then error(erkey);
  209.     lc2 := lc;
  210.     compoundstatement;
  211.     if sy = loopsy then insymbol else error(erkey);
  212.     emit1(15, lc2);
  213.     code[lc1].y := lc;
  214.     if listing then writeln(list, lc1:10, '   jump to here');
  215.   end;
  216.  
  217.   procedure standproc(n: integer);
  218.     { Compiles standard procedures:
  219.         get (read), skip_line (readln), put (write),
  220.         put_line and new_line (writeln), and
  221.         semaphore operations wait and signal. }
  222.   var i, f: integer;
  223.       x, y: item;
  224.   begin
  225.     case n of
  226.       1,2:
  227.        begin (* read *)
  228.        if sy = lparent then
  229.          begin
  230.            insymbol;
  231.            if sy <> ident then error(erid);
  232.            i := loc(level, id);
  233.            if i = 0 then error(ernf);
  234.            insymbol;
  235.            if tab[i].obj <> variable then error(ertyp);
  236.            x.typ := tab[i].typ;
  237.            x.ref := tab[i].ref;
  238.            if tab[i].normal then f := 0 else f := 1;
  239.            emit2(f, tab[i].lev, tab[i].adr);
  240.            if sy = lparent then
  241.              selector
  242.              (level, x);
  243.            if x.typ in [ints, chars, notyp] then emit1(27, ord(x.typ))
  244.              else error(ertyp);
  245.            if sy = rparent then insymbol else error(erpun)
  246.          end;
  247.          if n = 2 then emit(62)
  248.        end;
  249.  
  250.     3,4: (* write *)
  251.        begin
  252.        if sy = lparent then
  253.          begin
  254.            insymbol;
  255.            if sy = strng then
  256.              begin
  257.              emit1(24, sleng);
  258.              emit1(28, inum);
  259.              insymbol
  260.              end
  261.            else begin
  262.              expression(level, x);
  263.              if not (x.typ in stantyps) then error(ertyp);
  264.              emit1(29, ord(x.typ))
  265.              end;
  266.          if sy = rparent then insymbol else error(erpun)
  267.          end;
  268.          if n = 4 then emit(63)
  269.        end;
  270.  
  271.     5,6: (* wait, signal *)
  272.        begin
  273.          if sy <> lparent then error(erpun);
  274.          insymbol;
  275.          if sy <> ident then error(erid);
  276.          i := loc(level, id);
  277.          if i = 0 then error(ernf);
  278.          insymbol;
  279.          if tab[i].obj <> variable then error(ertyp);
  280.          x.typ := tab[i].typ;
  281.          x.ref := tab[i].ref;
  282.          if tab[i].normal then f := 0 else f := 1;
  283.          emit2(f, tab[i].lev, tab[i].adr);
  284.          if sy = lparent then selector(level, x);
  285.          if x.typ = ints then emit(n+1) else error(ertyp);
  286.          if sy = rparent then insymbol else error(erpun)
  287.        end
  288.     end (* case *)
  289.   end;
  290.  
  291.   procedure acceptstatement(var lcaccept: integer);
  292.     { accept E(I: in Integer; J: out Integer) do
  293.         S;
  294.       end E;    is compiled to:
  295.          lcaccept:  75  E
  296.                     76  I (level and address)
  297.                     S
  298.                     79  J (level and address)
  299.                     80  E
  300.      }
  301.  
  302.   var e: integer;   { index in entry table }
  303.       id1: alfa;    { save id to match with end }
  304.  
  305.       procedure skipacceptparms;
  306.         { skip accept parameter declaration, if entry already seen }
  307.       begin
  308.         insymbol;
  309.         if sy = lparent then
  310.           begin
  311.           repeat insymbol until sy = rparent;
  312.           insymbol
  313.           end
  314.       end;
  315.  
  316.       procedure acceptparms;
  317.         { accept statements may have zero, one or two parameters }
  318.  
  319.         procedure enterparm(var p: parmmode; var l: integer);
  320.           { accept parameters are implicitly declared in the
  321.             same block as the task (rather than declaring a
  322.             new scope). They should be of standard types
  323.             (integer, etc.) and can be of mode in or out
  324.             so that copy semantics can be used.
  325.             The procedure returns the mode of the parameter
  326.             and the symbol table index l of the variable.
  327.           }
  328.         var x: integer;
  329.             i: integer;
  330.         begin
  331.           insymbol;
  332.           if sy <> ident then error(erid);
  333.           i := loc(level, id);
  334.           if i = 0 then  { if non-existent, create a new variable }
  335.             begin
  336.             enter(id, variable, level);
  337.             i := t
  338.             end;
  339.           l := i;
  340.           p := inparm;
  341.           insymbol;
  342.           if sy <> colon then error(erpun);
  343.           insymbol;
  344.           if sy = outsy then begin p := outparm; insymbol end
  345.           else if sy = insy then insymbol;
  346.           if sy <> ident then error(ertyp);
  347.           x := loc(level, id);
  348.           if x = 0 then error(ertyp);
  349.           if tab[x].obj <> type1 then error(ertyp);
  350.           with tab[i] do
  351.             begin
  352.             typ := tab[x].typ;
  353.             ref := tab[x].ref;
  354.             lev := level;
  355.             normal := true;
  356.             adr := dx;
  357.             dx := dx + tab[x].adr
  358.             end;
  359.           insymbol
  360.         end;
  361.  
  362.       begin
  363.         { p1mode and p2mode store the modes and p1loc and p2loc
  364.           store the symbol table indices of the parameters.
  365.           This is important for out parameters which must have
  366.           the copy back compiled AFTER compiling the accept body. }
  367.         with entry[e] do       { assume initially no parameters }
  368.           begin
  369.           p1mode := noparm;
  370.           p2mode := noparm;
  371.           insymbol;
  372.           if sy = lparent then
  373.             begin
  374.             enterparm(p1mode, p1loc);   { first parameter }
  375.             if sy = rparent then insymbol
  376.             else if sy = semicolon then
  377.               begin
  378.               enterparm(p2mode, p2loc); { second parameter }
  379.               if sy <> rparent then error(erpun);
  380.               insymbol
  381.               end
  382.             end
  383.           end
  384.         end;
  385.  
  386.         procedure emitaccept1;
  387.         begin
  388.           lcaccept := lc;   { return the address of the accept
  389.                               which is used in the select statement }
  390.           emit1(75, e);     { start accept of entry e }
  391.           with entry[e] do
  392.             begin           { copy in parms, if any }
  393.             if p1mode = inparm then
  394.               emit2(76, tab[p1loc].lev, tab[p1loc].adr);
  395.             if p2mode = inparm then
  396.               emit2(77, tab[p2loc].lev, tab[p2loc].adr)
  397.             end
  398.         end;
  399.  
  400.         procedure emitaccept2;
  401.         begin
  402.           with entry[e] do
  403.             begin         { copy out parms, if any }
  404.             if p1mode = outparm then
  405.               emit2(78, tab[p1loc].lev, tab[p1loc].adr);
  406.             if p2mode = outparm then
  407.               emit2(79, tab[p2loc].lev, tab[p2loc].adr)
  408.             end;
  409.           emit1(80, e)    { complete accept of this entry }
  410.         end;
  411.  
  412.   begin
  413.       { The occurence of an entry name in an accept statement
  414.         defines that entry (i.e. we ignore the task specification).
  415.         Since there may be more than one accept for a given
  416.         entry, check if this entry has been previously defined.}
  417.     insymbol;
  418.     if sy <> ident then error(erid);
  419.     entry[0].taskid := curtask;  { sentinel for search }
  420.     entry[0].name := id;
  421.     id1 := id;     { save id to match end of accept }
  422.     e := entries;
  423.     while (entry[e].taskid <> curtask) or          { match task }
  424.           (entry[e].name   <> id) do e := e - 1;   { and entry name }
  425.     if e = 0 then   { new entry so allocate room in the entry table }
  426.       begin
  427.       entries := entries + 1;
  428.       e := entries;
  429.       if entries > emax then fatal(7);
  430.       with entry[entries] do
  431.         begin
  432.         taskid := curtask;
  433.         name := id;
  434.         open := 0;
  435.         waiting := 0;
  436.         acceptparms     { compile entry parameter declaration }
  437.         end
  438.       end
  439.     else skipacceptparms; { entry exists, so skip parameter declaration }
  440.     if sy <> semicolon then  { check for degenerate body }
  441.       begin
  442.       if sy <> dosy then error(erkey);
  443.       emitaccept1;         { instructions to commence accept }
  444.       compoundstatement;   { sequence of statements in body }
  445.       emitaccept2;         { instructions to complete accept }
  446.       if sy = ident then
  447.         begin
  448.         if id <> id1 then error(erid);
  449.         insymbol
  450.         end
  451.       end
  452.   end;
  453.  
  454.   procedure selectstatement;
  455.     { A select statement is compiled into a busy loop
  456.       that checks for rendezvous and depends on the time slicing
  457.       in the scheduler. After twice around the loop, the
  458.       process is suspended. This allows a random implementation
  459.       of the selection (see the interpreter).
  460.       Only two branches with a terminate alternative are allowed.
  461.  
  462.          select
  463.            when expr1 => accept E1 ...
  464.          or
  465.            when expr2 => accept E2 ...
  466.          end select;    is compiled to:
  467.  
  468.               81 - start select
  469.          lc0: expr1
  470.          lc1: jump to lca if false
  471.          lc5: accept E1 else jump to lca
  472.          lc2: jump to lcc
  473.          lca: expr2
  474.          lc3: jump to lcb if false
  475.          lc6: accept E2 else jump to lcb
  476.          lc4: jump to lcc
  477.          lcb: 82 - check terminate else skip next instruction
  478.               32 - end procedure (task)
  479.               83 - check if time to suspend
  480.          lcc: jump to lc0
  481.     }
  482.  
  483.   var lc0, lc1, lc2, lc3, lc4, lc5, lc6: integer;
  484.       x: item;
  485.   begin
  486.     insymbol;
  487.     emit(81);
  488.     lc0 := lc;
  489.     if sy <> when then emit1(24,1)
  490.       else begin
  491.       insymbol;
  492.       expression(level, x);
  493.       if not (x.typ in [bools, notyp]) then error(ertyp);
  494.       if sy <> arrow then error(erkey);
  495.       insymbol
  496.       end;
  497.     lc1 := lc;
  498.     emit(11);
  499.     acceptstatement(lc5);
  500.     if sy = semicolon then insymbol else error(erpun);
  501.     while sy in statbegsys do statement(dx, level);
  502.     lc2 := lc;
  503.     emit(10);
  504.     code[lc1].y := lc;
  505.     code[lc5].x := lc;
  506.     if listing then writeln(list, lc1:10, '   jump to here');
  507.     if listing then writeln(list, lc5:10, '   jump to here');
  508.     if sy = orsy then
  509.       begin
  510.       insymbol;
  511.       if sy <> when then emit1(24,1)  { if no guard, load true }
  512.         else begin
  513.         insymbol;
  514.         expression(level, x);
  515.         if not (x.typ in [bools, notyp]) then error(ertyp);
  516.         if sy <> arrow then error(erkey);
  517.         insymbol
  518.         end;
  519.       lc3 := lc;
  520.       emit(11);
  521.       acceptstatement(lc6);
  522.       if sy = semicolon then insymbol else error(erpun);
  523.       while sy in statbegsys do statement(dx, level);
  524.       lc4 := lc;
  525.       emit(10);
  526.       code[lc3].y := lc;
  527.       code[lc6].x := lc;
  528.       if listing then writeln(list, lc3:10, '   jump to here');
  529.       if listing then writeln(list, lc6:10, '   jump to here');
  530.       end;
  531.     if sy = orsy then
  532.       begin
  533.       insymbol;
  534.       if sy <> terminate then error(erkey) else insymbol;
  535.       if sy <> semicolon then error(erkey) else insymbol;
  536.       emit(82);
  537.       emit(32)
  538.       end;
  539.     emit(83);
  540.     emit1(10,lc0);
  541.     code[lc2].y := lc;
  542.     code[lc4].y := lc;
  543.     if listing then writeln(list, lc2:10, '   jump to here');
  544.     if listing then writeln(list, lc4:10, '   jump to here');
  545.     if sy = endsy then insymbol else error(erkey);
  546.     if sy = selectsy then insymbol else error(erkey);
  547.   end;
  548.  
  549.   procedure entrycall(x: integer);
  550.     { Compile entry call.
  551.          Must be compiled AFTER task BODY containing the accept.
  552.            T.E(expr1, var2) will be compiled to:
  553.               expr1
  554.               70
  555.               73  I (level and address)
  556.               74
  557.     }
  558.   var e: integer;
  559.       i: integer;
  560.       j: item;
  561.   begin
  562.     if sy <> period then error(erpun);
  563.     insymbol;
  564.     if sy <> ident then error(erid);
  565.     entry[0].taskid := x;   { Search for match in entry table }
  566.     entry[0].name := id;
  567.     e := entries;
  568.     while (entry[e].taskid <> x) or
  569.           (entry[e].name <> id) do e := e - 1;
  570.     if e = 0 then error(erid);
  571.     insymbol;
  572.     with entry[e] do
  573.       if p1mode <> noparm then
  574.         begin
  575.         if sy <> lparent then error(erpun);
  576.         insymbol;
  577.         if p1mode = inparm then  { First parameter is in mode }
  578.           begin                  { so compile expression }
  579.           expression(level, j);
  580.           emit(70)
  581.           end
  582.         else
  583.           begin                  { First parameter is out mode }
  584.           i := loc(level, id);   {  so emit instruction with address }
  585.           emit2(72, tab[i].lev, tab[i].adr);
  586.           insymbol
  587.           end;
  588.         if p2mode <> noparm then { Similarly, for second parameter }
  589.           begin
  590.           if sy <> comma then error(erpun);
  591.           insymbol;
  592.           if p2mode = inparm then
  593.             begin
  594.             expression(level, j);
  595.             emit(71)
  596.             end
  597.           else
  598.             begin
  599.             i := loc(level, id);
  600.             emit2(73, tab[i].lev, tab[i].adr);
  601.             insymbol
  602.             end
  603.           end;
  604.         if sy = rparent then insymbol else error(erpun)
  605.         end;
  606.     emit1(74, e)     { Call entry }
  607.   end;
  608.  
  609.   begin (* statement *)
  610.     if sy in statbegsys then
  611.       case sy of
  612.         ident:   { assignment or procedure calls }
  613.           begin
  614.           i := loc(level, id);
  615.           insymbol;
  616.           if i = 0 then error(ernf);
  617.           if tab[i].obj = variable then
  618.              assignment(level, i, tab[i].lev, tab[i].adr)
  619.           else if tab[i].obj = prozedure then
  620.              if tab[i].lev <> 0 then call(level, i)
  621.              else standproc(tab[i].adr)
  622.           else if tab[i].obj = task then
  623.             entrycall(i)
  624.           else error(ertyp)
  625.           end;
  626.  
  627.         acceptsy: acceptstatement(lcx);
  628.         ifsy:     ifstatement;
  629.         whilesy:  whilestatement;
  630.         loopsy:   loopstatement;
  631.         forsy:    forstatement;
  632.         selectsy: selectstatement;
  633.         nullsy:   insymbol;
  634.       end (* case *);
  635.     if sy = semicolon then insymbol else error(erpun);
  636.   end;
  637.  
  638. end.